import { encryptBase64, encryptWithAes, generateAesKey } from "../tools/crypto";
import { encrypt } from "../tools/jsencrypt";

// 文件名：http-request.ts
const { ccclass } = cc._decorator;

/**
 * HTTP 请求配置项
 */
interface RequestConfig {
  url: string; // 请求地址
  method?: 'GET' | 'POST'; // 请求方法 (默认GET)
  headers?: { [key: string]: string | boolean }; // 请求头
  data?: any; // POST请求的数据体
  params?: { [key: string]: string }; // GET请求的URL参数
  timeout?: number; // 超时时间 (默认10000ms)
}

/**
 * 全局请求配置
 */
const GLOBAL_CONFIG = {
  baseURL: 'http://localhost:8088', // 基础URL
  timeout: 10000, // 默认超时时间
  getToken: () => { // 获取Token的方法 (需根据项目实际存储方式实现)
    return cc.sys.localStorage.getItem('authToken') || '';
  }
};

/**
 * 封装后的HTTP请求方法
 * @param config 请求配置
 * @returns Promise<unknown>
 * 
 */
export function request<T = any>(config: RequestConfig): Promise<T> {
  return new Promise((resolve, reject) => {
    // 合并全局配置
    const fullUrl = GLOBAL_CONFIG.baseURL + config.url;
    const method = config.method || 'GET';
    const timeout = config.timeout || GLOBAL_CONFIG.timeout;

    // 创建XMLHttpRequest对象
    const xhr = new XMLHttpRequest();

    // 设置请求超时
    xhr.timeout = timeout;

    // 处理GET参数
    let requestUrl = fullUrl;
    if (method === 'GET' && config.params) {
      const params = new URLSearchParams(config.params).toString();
      requestUrl += `?${params}`;
    }

    // 初始化请求
    xhr.open(method, requestUrl, true);

    // 如果需要加密，对 data 进行加密
    const isEncrypt = config.headers?.isEncrypt === true;
    if (isEncrypt && (method === 'POST' || method === 'PUT')) {
      // 生成一个 AES 密钥
      const aesKey = generateAesKey();
      const encryptHeader = 'encrypt-key';

      config.headers[encryptHeader] = encrypt(encryptBase64(aesKey));;

      // 对请求数据进行 AES 加密
      if (config.data instanceof FormData) {
        // 处理 FormData
        delete config.headers['Content-Type'];
        const formDataObj = {};
        config.data.forEach((value, key) => {
          formDataObj[key] = value;
        });
      } else {
        // 处理普通对象或字符串
        config.data = typeof config.data === 'object' 
            ? encryptWithAes(JSON.stringify(config.data), aesKey) 
            : encryptWithAes(config.data, aesKey);
      }
    }

    // 设置请求头 (包含Token)
    const headers = {
      'Content-Type': 'application/json',
      'Authorization': `Bearer ${GLOBAL_CONFIG.getToken()}`,
      clientid: 'e5cd7e4891bf95d1d19206ce24a7b32e',
      ...config.headers
    };
    cc.log(config.headers)
    Object.entries(headers).forEach(([key, value]) => {
      xhr.setRequestHeader(key, value);
    });

    // 设置回调
    xhr.onload = () => {
      if (xhr.status >= 200 && xhr.status < 300) {
        try {
          const data = JSON.parse(xhr.responseText);
          // 此处可根据后端接口规范调整判断逻辑
          if (data.code === 200) {
            resolve(data.data);
          } else {
            showError(data.msg || '请求失败');
            reject(data);
          }
        } catch (e) {
          showError('响应解析失败');
          reject(e);
        }
      } else {
        handleError(new Error(`HTTP 错误: ${xhr.status}`));
        reject(new Error(`HTTP 错误: ${xhr.status}`));
      }
    };

    xhr.onerror = () => {
      handleError(new Error('网络请求失败'));
      reject(new Error('网络请求失败'));
    };

    xhr.ontimeout = () => {
      handleError(new Error('请求超时'));
      reject(new Error('请求超时'));
    };

    // 发送请求
    if (method === 'POST' || method === 'PUT') {
      xhr.send(JSON.stringify(config.data));
    } else {
      xhr.send();
    }
  });
}

/**
 * 统一错误处理
 * @param error 错误对象
 */
function handleError(error: Error) {
  console.error('Request Error:', error);
  showError(error.message || '网络请求失败');
}

/**
 * 显示错误提示 (使用Cocos原生提示框)
 * @param message 错误信息
 */
function showError(message: string) {
  cc.log('显示错误提示:', message);
  // 此处可替换为项目使用的UI提示组件
  const label = new cc.Node().addComponent(cc.Label);
  label.string = message;
  label.node.color = cc.Color.RED;
  label.node.parent = cc.director.getScene();
  label.node.setPosition(0, 0);
  cc.tween(label.node)
    .delay(2)  // 延迟 2 秒
    .call(() => {
        label.node.destroy();  // 移除节点
    })
    .start();
}

// ------------------- 业务接口封装 ------------------- //

